#include "stdafx.h"
#include "MouseTracerManagerImpl3.h"
#include "MouseTracer.h"
#include "MGCfg.h"
#include "TUtils.h"

HHOOK CMouseTracerManagerImpl3::m_hHook = NULL;
CMouseTracer<CMouseTracerManager<CMouseTracerManagerImpl3> > *CMouseTracerManagerImpl3::m_pTracer = NULL;
BOOL CMouseTracerManagerImpl3::m_bTracerDeleted = TRUE;

CMouseTracerManagerImpl3::CMouseTracerManagerImpl3()
{
	AUTO_MUTEX(CMouseTracerManagerImpl3);
}

CMouseTracerManagerImpl3::~CMouseTracerManagerImpl3()
{
	AUTO_MUTEX(CMouseTracerManagerImpl3);
	
	if (m_hHook)
	{
		::UnhookWindowsHookEx(m_hHook);
		m_hHook = NULL;
	}
	
	// m_pTracer will be automatically deleted on receiving WM_NCDESTROY
}

/**
*	CMouseTracerManagerImpl3::Setup(HINSTANCE hMod)
*
*
*	@return BOOL
*
*/

BOOL CMouseTracerManagerImpl3::Setup(HINSTANCE hMod/* = NULL*/, DWORD dwThreadID/* = 0*/)
{
	AUTO_MUTEX(CMouseTracerManagerImpl3);
	
	if (m_hHook)
		return TRUE;
	
	if(hMod == NULL)
		hMod = (HINSTANCE)::GetModuleHandle(NULL);
	
	if(dwThreadID == 0)
		dwThreadID = ::GetCurrentThreadId();
	m_hHook = ::SetWindowsHookEx(WH_MOUSE, MouseProc, hMod, dwThreadID);
	
	return !(m_hHook == NULL);
}

/**
*	CMouseTracerManagerImpl3::Remove()
*
*
*	@return void
*
*/

void CMouseTracerManagerImpl3::Remove(DWORD/* dwThreadID = 0*/)
{
	AUTO_MUTEX(CMouseTracerManagerImpl3);
	
	if (m_hHook)
	{
		::UnhookWindowsHookEx(m_hHook);
		m_hHook = NULL;
	}
	
	if (m_pTracer && !CMouseTracerManagerImpl3::m_bTracerDeleted)
	{
		if (::IsWindow(m_pTracer->GetHwnd()))
		{
			m_pTracer->Unhook();
			m_pTracer->Delete();
			m_pTracer = NULL;
		}
	}
}

typedef CMouseTracer<CMouseTracerManager<CMouseTracerManagerImpl3> > MouseTracer;

/**
*	CMouseTracerManagerImpl3::MouseProc()
*
*	@param int nCode
*	@param WPARAM wParam
*	@param LPARAM lParam
*
*	@return LRESULT CALLBACK
*
*/
LRESULT CALLBACK CMouseTracerManagerImpl3::MouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
	if(nCode < 0)
		return ::CallNextHookEx(m_hHook, nCode, wParam, lParam);
	
	if (nCode == HC_ACTION)
	{
		if (lParam)
		{
#if(_WIN32_WINNT >= 0x0500)
			MOUSEHOOKSTRUCTEX *pMHEX = reinterpret_cast<MOUSEHOOKSTRUCTEX *>(lParam);
			MOUSEHOOKSTRUCT *pMH = (MOUSEHOOKSTRUCT *)pMHEX;
#else	// #if(_WIN32_WINNT >= 0x0500)
			MOUSEHOOKSTRUCT *pMH = reinterpret_cast<MOUSEHOOKSTRUCT *>(lParam);
#endif	// #if(_WIN32_WINNT >= 0x0500)
			
			int nCatTarget;
			switch (wParam)
			{
			case WM_RBUTTONDOWN:
			case WM_NCRBUTTONDOWN:
				if (MGCfg::Get().Option().GetMGAButton() == MG::BUTTON_RIGHT)
				{
					AUTO_MUTEX(CMouseTracerManagerImpl3);
					
					if ((m_pTracer && !m_pTracer->IsTemporarySuspended()) || !m_pTracer)
					{
						if (m_pTracer && MGCfg::Get().Option().IsShowRecognitionOnStatusBar() && MGCfg::Get().Option().IsIdentifyTargetWindowClass())
							MGCfg::Get().Action().IdentifyTargetWindowClass(pMH->hwnd);
						
						if(!MGCfg::Get().Action().IsMGInAction())
						{
							if (-1 != (nCatTarget = MGCfg::Get().Action().CheckTargetValid(pMH->hwnd)))
							{
								if (m_pTracer && !CMouseTracerManagerImpl3::m_bTracerDeleted)
								{
									if (m_pTracer->GetHwnd() != pMH->hwnd)
									{
										// check to see if the hooked window have already been destroyed
										if (::IsWindow(m_pTracer->GetHwnd()))
										{
											m_pTracer->Unhook();
											m_pTracer->Delete();
											m_pTracer = NULL;
										}
									}
									else
										break;
								}

								m_pTracer = (MouseTracer *)new MouseTracer(TRUE, &CMouseTracerManagerImpl3::m_bTracerDeleted);
								m_pTracer->Hook(pMH->hwnd);
								m_pTracer->SetTargetCategory((BYTE)nCatTarget);
							}
						}
					}
				}
				break;
				
			case WM_MBUTTONDOWN:
			case WM_NCMBUTTONDOWN:
				if (MGCfg::Get().Option().GetMGAButton() == MG::BUTTON_MIDDLE)
				{
					AUTO_MUTEX(CMouseTracerManagerImpl3);
					
					if ((m_pTracer && !m_pTracer->IsTemporarySuspended()) || !m_pTracer)
					{
						if (m_pTracer && MGCfg::Get().Option().IsShowRecognitionOnStatusBar()
							&& MGCfg::Get().Option().IsIdentifyTargetWindowClass())
							MGCfg::Get().Action().IdentifyTargetWindowClass(pMH->hwnd);
						
						if(!MGCfg::Get().Action().IsMGInAction())
						{
							if (-1 != (nCatTarget = MGCfg::Get().Action().CheckTargetValid(pMH->hwnd)))
							{
								if (m_pTracer && !CMouseTracerManagerImpl3::m_bTracerDeleted)
								{
									if (m_pTracer->GetHwnd() != pMH->hwnd)
									{
										if (::IsWindow(m_pTracer->GetHwnd()))
										{
											m_pTracer->Unhook();
											m_pTracer->Delete();
											m_pTracer = NULL;
										}
									}
									else 
										break;
								}
								m_pTracer = (MouseTracer *)new MouseTracer(TRUE, &CMouseTracerManagerImpl3::m_bTracerDeleted);
								m_pTracer->Hook(pMH->hwnd);
								m_pTracer->SetTargetCategory((BYTE)nCatTarget);
							}
						}
					}
				}
				break;
				
			case WM_RBUTTONDBLCLK:
			case WM_LBUTTONDBLCLK:
			case WM_MBUTTONDBLCLK:
				if ((nCatTarget = MGCfg::Get().Action().CheckTargetValid(pMH->hwnd)) != -1)
				{
					AUTO_MUTEX(CMouseTracerManagerImpl3);
					
					if ((m_pTracer && !m_pTracer->HasMouseCapture()) || !m_pTracer)
					{
						if (m_pTracer && !CMouseTracerManagerImpl3::m_bTracerDeleted)
						{
							if (m_pTracer->GetHwnd() != pMH->hwnd)
							{
								if (::IsWindow(m_pTracer->GetHwnd()))
								{
									HWND hWnd = m_pTracer->Unhook();
									m_pTracer->Delete();
									m_pTracer = NULL;
								}
							}
							else 
								break;
						}
						m_pTracer = (MouseTracer *)new MouseTracer(TRUE, &CMouseTracerManagerImpl3::m_bTracerDeleted);
						m_pTracer->Hook(pMH->hwnd);
						m_pTracer->SetTargetCategory((BYTE)nCatTarget);
						TRACE(_T("%s to install a mouse tracer to (%x)\n"), m_pTracer ? _T("Succeeded") : _T("Failed"), pMH->hwnd);
					}
				}
				break;
			}
		}
	}
	
	return ::CallNextHookEx(m_hHook, nCode, wParam, lParam);
}
